001    /* $RCSfile: RIPEMD160MessageDigestEngine.java,v $
002     * $Revision: 1.6 $
003     * $Date: 2003/10/04 19:18:38 $
004     * $Author: uwe_guenther $
005     * $State: Exp $
006     *
007     * Created on July 4, 2001, 1:01 PM
008     *
009     * Copyright (C) 2001 Uwe Guenther <uwe@cscc.de>
010     *
011     * This file is part of the jhbci JCE-ServiceProvider. The jhbci JCE-
012     * ServiceProvider is a library, written in JavaTM, that should be 
013     * used in HBCI banking applications (clients and may be servers),
014     * to do cryptographic operations.
015     *
016     * The jhbci library is free software; you can redistribute it and/or
017     * modify it under the terms of the GNU Lesser General Public
018     * License as published by the Free Software Foundation; either
019     * version 2.1 of the License, or (at your option) any later version.
020     *
021     * The jhbci library is distributed in the hope that it will be useful,
022     * but WITHOUT ANY WARRANTY; without even the implied warranty of
023     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
024     * Lesser General Public License for more details.
025     *
026     * You should have received a copy of the GNU Lesser General Public
027     * License along with this library; if not, write to the Free Software
028     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
029     *
030     */
031    
032    package de.cscc.crypto.provider;
033    
034    import java.security.DigestException;
035    import java.security.MessageDigestSpi;
036    
037    /**
038     * RIPEMD160MessageDigestEngine Class.
039     * 
040     * This class does the RIPEMD-160 algorithm via delegation to 
041     * RIPEMD160MessageDigestImpl and is implemented as JCA (Java Cryptogrphy Architecture)
042     * Service Provider. You can not instance these class
043     * direct, because it is enabled through the JCA API.
044     *
045     *
046     * <p>The sum of all added bytes from {@link #engineUpdate(byte)
047     * engineUpdate(byte)} and {@link #engineUpdate(byte[], int, int) 
048     * engineUpdate(byte[], int, int)} are processed by the RIPEMD-160
049     * message digest algorithm with {@link #engineDigest() engineDigest()} or
050     * {@link #engineDigest(byte[] , int, int) engineDigest(byte[], int, int)}.
051     *
052     * <pre>
053     *
054     * How does it work:
055     * =================
056     *
057     * RIPEMD-160 works only with whole 512 bit blocks.
058     *
059     *        512bits == 64 bytes == 16 words
060     * -------------------------------------------------
061     * |00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|
062     * -------------------------------------------------
063     *                    /  \
064     *                   /    \
065     *                  /      \
066     *                 /        \
067     *                /          \
068     *               -------------
069     *               |32 bit word|   <-- 32 bit word = 4 byte
070     *               -------------
071     *               |00|01|02|03|   <-- 4 bytes = 4 x 8 bit = 32 bit
072     *               -------------
073     *
074     * </pre>
075     *
076     * <p>Here is a simple Code Example:
077     * 
078     * <pre>
079     *
080     * import java.security.Security;
081     * import java.security.Provider;
082     * import java.security.MessageDigest;
083     * import java.security.NoSuchAlgorithmException;
084     * import de.cscc.crypto.provider.HBCI;
085     * import java.io.IOException;
086     *
087     * public class MyMessageDigest{
088     *  public static void main(String args[]){
089     *   
090     *    // add Provider
091     *    int i = Security.addProvider(new de.cscc.crypto.provider.JHBCI());
092     *    System.out.println("Provider inserted at position " + i + ".");
093     *
094     *    // get provider
095     *    Provider p = Security.getProvider("JHBCI");
096     *    System.out.println("My Provider Name is " + p.getName());
097     *    System.out.println("My Provider Version is " + p.getVersion());
098     *    System.out.println("My Provider Info is " + p.getInfo());
099     *
100     *    // get MessageDigest Object through the JCA API
101     *    MessageDigest myRIPEMD1 = null;
102     *    MessageDigest myRIPEMD2 = null,
103     *
104     *    try{
105     *        myRIPEMD1 = MessageDigest.getInstance("RIPEMD160");
106     *    } catch(NoSuchAlgorithmException e){
107     *        e.printStackTrace();
108     *    }
109     *
110     *    // put the messaeg in the MessageDigest object
111     *    byte[] myByte = {'a','b','c'};
112     *    myRIPEMD1.update(myByte);
113     *
114     *    // clone the object
115     *    try {
116     *        myRIPEMD2 = myRIPEMD1.clone
117     *    } catch (CloneNotSupportedException e) {
118     *        e.printStackTrace();
119     *    }
120     *
121     *    // get the Message Digests
122     *    byte[] messageDigest1 = myRIPEMD1.digest();
123     *    byte[] messageDigest2 = myRIPEMD2.digest();
124     *
125     *    // now the byte arrays messageDigest[12] holds a 20 byte long message
126     *    // digest of the message "abc" and should be in binary form:
127     *    // 0x8eb208f7e05d987a9b044a8e98c6b087f15a0bfc
128     *
129     *    // verify the two digests
130     *    boolean verify = MessageDigest.isEqual(messageDigest1, messageDigest2);
131     *    System.out.println("The two digests are equal: " + verify);
132     *  }
133     * }
134     * </pre>
135     *
136     * @author  <a href=mailto:uwe@cscc.de>Uwe Günther</a>
137     * @version $Revision: 1.6 $
138     */
139    public final class RIPEMD160MessageDigestEngine 
140    extends MessageDigestSpi implements Cloneable {
141    
142        /**
143         * Object to which we delegate all working crypto stuff from these method.
144         */    
145        private RIPEMD160MessageDigestImpl md = 
146        new RIPEMD160MessageDigestImpl();
147        
148        /**
149         * Creates new RIPEMD160MessageDigestEngine. This default constructor is
150         * invoked from <code>java.security.MessageDigest.getInstance()</code>.
151         */
152        public RIPEMD160MessageDigestEngine() {
153            if (JHBCI.selfIntegrityChecking() == false) {
154                throw new SecurityException("JHBCI-Provider is tampered.");
155            }    
156        }
157        
158        /** 
159         * Creates and returns a deep of this object.
160         * @return a clone of this instance.
161         * @see java.lang.Cloneable
162         * @exception CloneNotSupportedException if the object's class does not
163         *             support the <code>Cloneable</code> interface. Subclasses
164         *             that override the <code>clone</code> method can also
165         *             throw this exception to indicate that an instance cannot
166         *             be cloned.
167         */
168        public Object clone() throws CloneNotSupportedException {
169            RIPEMD160MessageDigestEngine result = 
170            (RIPEMD160MessageDigestEngine) super.clone();
171            result.md = (RIPEMD160MessageDigestImpl) this.md.clone();
172            return result;
173        }        
174        
175        /**
176         * Compares two RIPEMD160MessageDigestEngine objects. If the private members
177         * of obj are equal wtih the private members of this object the method
178         * will return true, otherwise false.
179         * @param obj RIPEMD160MessageDigestEngine object to compare.
180         * @return true if the objects are deeply equal.
181         */    
182        public boolean equals(Object obj) {
183            //Only for performance.
184            if (this == obj) {
185                return true;
186            } 
187            
188            //If obj == null then instanceof returns false, see JLS 15.20.2
189            if (!(obj instanceof RIPEMD160MessageDigestEngine)) {           
190                 return false;
191            }
192             
193            RIPEMD160MessageDigestEngine other = (RIPEMD160MessageDigestEngine)obj;
194            return this.md.equals(other.md);
195        }
196        
197        /** 
198         * Returns a hash code value for the object. This method is
199         * supported for the benefit of hashtables such as those provided by
200         * <code>java.util.Hashtable</code>.
201         *
202         * @return  a hash code value for this object.
203         * @see     #equals(java.lang.Object)
204         * @see     java.util.Hashtable
205         */
206        public int hashCode() {
207            int result = 17;
208            result = 37*result + this.md.hashCode();
209            return result;
210        }        
211        
212        /**
213         * Returns a string representation of the object. 
214         * @return  a string representation of the object.
215         */
216        public String toString() {
217            return this.md.toString();
218        }
219        
220        /**
221         * If the whole message added to the message digest object, you should
222         * invoke the digest method at your API object (MessageDigest). The wraper
223         * invokes these method to return the 160 bit RIPEMD-160 digest at a byte
224         * array (20 byte or 160 bit).
225         * @return the message digest in 20 byte long byte array.
226         * This byte array contains the 160 bit digest in binary form.
227         */
228        protected byte[] engineDigest() {
229            return this.md.digest();
230        }
231        
232        /**
233         * If the whole message added to the message digest object, you should
234         * invoke the digest method at your API Object (MessageDigest). The Wraper
235         * invokes these method to return the 160 bit RIPEMD-160 digest at a byte
236         * array (20 byte or 160 bit).
237         * @param buf the message digest in 20 byte long byte array.
238         * This byte array contains the 160 bit digest in binary form.
239         * @param offset begin of buffer.
240         * @param len end of buffer.
241         * @throws DigestException If the difference between len-offset less than
242         * 20 bytes a DigestException will be thrown.
243         * @return the length of the digest stored in the output buffer.
244         */
245        protected int engineDigest(byte[] buf, int offset, int len) 
246        throws DigestException {
247            return this.md.digest(buf, offset, len);
248        }
249        
250        /**
251         * Returns the length of the message digest in byte. In case of RIPEMD-160
252         * it will be 20.
253         * @return digest length (20) in byte.
254         */
255        protected int engineGetDigestLength() {
256            return this.md.getDigestLength();
257        }
258        
259        /** Resets the message digest object, for further use. So if you have
260         * calculated your digest, you should invoke reset() through the JCA API 
261         * that invokes this engineReset method to reset the object to calculate an 
262         * new digest from a new message.
263         */
264        protected void engineReset() {
265            this.md.reset();
266        }
267        
268        /**
269         * Updates the internal message buffer with <CODE>byte value</CODE>.
270         * @param value message byte.
271         */
272        protected void engineUpdate(byte value) {
273            this.md.update(value);
274        }
275        
276        /**
277         * Updates the internal message buffer with <CODE>byte[] value</CODE>,
278         * starting at offset, ending at len.
279         * @param values message byte array.
280         * @param offset begin of message byte array.
281         * @param len end of message byte array.
282         */
283        protected void engineUpdate(byte[] values, int offset, int len) {
284            this.md.update(values, offset, len);
285        }
286    }